home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1990-1992 Michael Davidson.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation.
- *
- * This software is provided "as is" without express or implied warranty.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <setjmp.h>
- #include <unistd.h>
- #include <stdarg.h>
-
- #include "vg.h"
- #include "image.h"
- #include "kbd.h"
- #include "text.h"
- #include "video.h"
-
-
- image_t *DisplayedImage = NULL;
- image_t *Image = NULL;
-
- STATIC int ImageX = 0;
- STATIC int ImageY = 0;
- STATIC color_t ImageColorMap[256];
- STATIC int ImageBackground = 0;
-
- STATIC int ImageDefaultDelay = -1;
-
- STATIC unsigned long ImageHistogram[32 * 1024];
-
- STATIC int ScreenMode = -1;
- STATIC vmode_t *ScreenModeInfo = NULL;
-
- STATIC char ImageName[80];
- STATIC int ImageInfoFlag = 0;
- STATIC unsigned ImageInfoX;
- STATIC unsigned ImageInfoY;
- STATIC unsigned ImageInfoWidth;
- STATIC unsigned ImageInfoHeight;
- STATIC void ImageInfo(int);
-
- int bestDisplayMode(int, int, int, int);
-
- STATIC void (*Redraw)();
- STATIC void IRedraw8();
- STATIC void IRedraw24();
- int imageRedraw();
- void imageShowInfo(int);
-
- int
- imageInit()
- {
- return 0;
- }
-
- image_t *
- imageAlloc(
- int width,
- int height,
- int depth)
- {
- image_t *image;
- int nbytes;
- int bytes_per_pixel;
- int i;
- unsigned char *p;
-
- bytes_per_pixel = (depth + 7) / 8;
- nbytes = sizeof(image_t)
- + (height * sizeof(unsigned char *))
- + (width * height * bytes_per_pixel);
-
- if ((image = malloc(nbytes)) == NULL)
- return NULL;
-
- image->width = width;
- image->height = height;
- image->depth = depth;
- image->bytes_per_pixel = bytes_per_pixel;
- image->pixels = (unsigned char **) (image + 1);
-
- p = (unsigned char *) (image->pixels + height);
-
- for (i = 0; i < height; i++)
- {
- image->pixels[i] = p;
- p += width * bytes_per_pixel;
- }
-
- return image;
- }
-
- STATIC void
- imagePixelLookupInit()
- {
- int i, j, k;
- unsigned r, g, b;
- unsigned char *l = &VPixelLookup[0];
-
- for (i = 0, r = 0; i < 32; i++, r += 77)
- for (j = 0, g = 0; j < 32; j++, g += 150)
- for (k = 0, b = 0; k < 32; k++, b += 29)
- {
- *l++ = (r + g + b) / 32;
- }
- }
-
- void
- imageSetGrayColorMap(
- unsigned maxgray
- )
- {
- int i;
-
- if (maxgray > 255)
- fatal(-1, "imageSetGrayColorMap() - gray level > 255 (%d)", maxgray);
-
- for (i = 0; i <= maxgray; i++)
- {
- ImageColorMap[i].red =
- ImageColorMap[i].green =
- ImageColorMap[i].blue = i;
- }
- vidSetPalette(ImageColorMap, 256);
- }
-
- void
- imageSetName(
- char *name
- )
- {
- strncpy(ImageName, name, 40);
- }
-
-
- void
- imageSetDefaultDelay(
- int delay
- )
- {
- ImageDefaultDelay = delay;
- }
-
- void
- imageSetGamma(
- long RedGamma,
- long GreenGamma,
- long BlueGamma
- )
- {
- vidSetGamma(RedGamma, GreenGamma, BlueGamma);
- vidSetPalette(ImageColorMap, 256);
- if (ScreenModeInfo->depth > 8)
- {
- IRedraw(0, 0, ScreenModeInfo->width, ScreenModeInfo->height);
- imageShowInfo(ImageInfoFlag);
- }
- }
-
- void
- imageShowInfo(
- int flag
- )
- {
- char buf[120];
- int len;
- font_t *font = DefaultFont;
-
- if (flag == 0)
- {
- if (ImageInfoFlag)
- {
- ImageInfoFlag = 0;
- IRedraw(ImageInfoX, ImageInfoY, ImageInfoWidth, ImageInfoHeight);
- }
- return;
- }
-
- sprintf(buf, "%s %dx%d-%d ", ImageName,
- Image->width, Image->height, Image->depth);
- len = strlen(buf);
-
- if ( Image->width > ScreenModeInfo->width
- || Image->height > ScreenModeInfo->height
- || Image->depth > ScreenModeInfo->depth )
- {
- sprintf(&buf[len], " (%dx%d-%d)", ScreenModeInfo->width,
- ScreenModeInfo->height, ScreenModeInfo->depth);
- len = strlen(buf);
- }
-
- if (len > ScreenModeInfo->width / font->f_width)
- len = ScreenModeInfo->width / font->f_width;
-
- ImageInfoX = (ScreenModeInfo->width - font->f_width * len) / 2;
- ImageInfoY = ScreenModeInfo->height - font->f_height * 2;
- ImageInfoWidth = len * font->f_width;
- ImageInfoHeight = font->f_height;
-
- vidDrawText(ImageInfoX, ImageInfoY, buf, len, font);
-
- ImageInfoFlag = flag;
- }
-
- image_t *
- imageStart(
- char *name,
- int width,
- int height,
- int depth,
- int background
- )
- {
- int i;
- vmode_t *m;
- int bpp;
-
- /*
- * round up width to a multiple of 8 pixels
- */
- if (width & 7)
- width = (width & ~7) + 8;
-
- i = bestDisplayMode(V_GRAPHICS_MODE, width, height, depth);
- m = vidModeInfo(i);
-
- if (depth <= 8)
- {
- if (m->depth < depth || m->depth > 8)
- return NULL;
-
- bpp = 1;
- Redraw = IRedraw8;
- }
- else if (depth == 24)
- {
- bpp = 3;
- Redraw = IRedraw24;
- }
- else
- fatal(-1, "ImageStart(): bad depth = %d", depth);
-
- if (width < m->width)
- width = m->width;
- if (height < m->height)
- height = m->height;
-
- /*
- * try to re-use the existing image buffer if possible
- */
- if ( Image == NULL || width != Image->width || height != Image->height
- || bpp != Image->bytes_per_pixel)
- {
- if (Image != NULL)
- free(Image);
-
- if ((Image = imageAlloc(width, height, depth)) == NULL)
- return NULL;
- }
-
- DisplayedImage = Image;
- ImageX = 0;
- ImageY = 0;
-
- ImageBackground = background;
-
-
- if (ScreenMode != i || vidGetMode() != i)
- {
- vidSetGraphicsRedraw(imageRedraw);
- if (vidSetMode(i) != 0)
- return NULL;
- ScreenMode = i;
- ScreenModeInfo = m;
- }
-
- imageClear(Image, ImageBackground);
-
- imageSetGamma(70, 70, 70);
-
- if (Image->depth > 8)
- {
- imagePixelLookupInit();
- imageSetGrayColorMap(255);
- }
-
- imageSetName(name);
-
- return Image;
- }
-
- imageClear(
- image_t *image,
- int color
- )
- {
- int i;
-
- if (image == DisplayedImage)
- vidClear(color);
-
- for (i = 0; i < image->height; i++)
- memset(image->pixels[i], color, image->width * image->bytes_per_pixel);
- }
-
- /*ARGSUSED*/
- void
- imageSetColorMap(
- int flag,
- color_t *cmap,
- int n
- )
- {
- vidSetPalette(cmap, n);
- memcpy(ImageColorMap, cmap, n * sizeof(color_t));
- }
-
- int
- imagePutPixels(
- int x,
- int y,
- void *pix,
- int n
- )
- {
- if (Image->bytes_per_pixel != 1)
- return -1;
-
- memcpy(Image->pixels[y] + x, pix, n);
- return imageRefresh(x, y, n, 1);
- }
-
- int
- imagePutPixelsRGB(
- int x,
- int y,
- void *pix,
- int n
- )
- {
- if (Image->bytes_per_pixel != 3)
- return -1;
-
- memcpy(Image->pixels[y] + x * 3, pix, n * 3);
-
- return imageRefresh(x, y, n, 1);
- }
-
-
- int
- imageRefresh(
- int x,
- int y,
- int w,
- int h
- )
- {
- static int count = 0;
-
- IRedraw(x - ImageX, y - ImageY, w, h);
-
- if ((count += h) > 16)
- {
- count = 0;
- return imageGetKey(0);
- }
- return 0;
- }
-
- imageEnd()
- {
- int k;
- int r;
-
- if (Image->depth == 24 && ScreenModeInfo->depth == 8)
- {
- CreateHistogram24(Image->pixels, Image->width, Image->height,
- ImageHistogram);
- quantize(ImageHistogram, ImageColorMap, VPixelLookup, 256);
- if ((r = imageRedraw()) != 0)
- return r;
- }
-
- if (ImageDefaultDelay == 0)
- return F_NEXT;
-
- if (ImageDefaultDelay > 0 && ImageDefaultDelay < 2)
- {
- k = imageGetKey(ImageDefaultDelay);
- return (k > 0) ? k : F_NEXT;
- }
-
- k = imageGetKey(2);
- imageShowInfo(0);
-
- if (k > 0)
- return k;
-
- if (ImageDefaultDelay > 0)
- {
- k = imageGetKey(ImageDefaultDelay - 2);
- return (k > 0) ? k : F_NEXT;
- }
-
- r = imageGetKey(K_WAIT);
- return r;
- }
-
- imageGetKey(
- int delay
- )
- {
-
- int k;
-
- do
- {
- k = kbdGetKey(delay);
-
- switch (k)
- {
- case K_ENTER:
- case 'n':
- case 'N':
- return F_NEXT;
-
- case 'p':
- case 'P':
- return F_PREV;
-
- case 'r':
- return F_REDRAW;
-
- case K_LEFT:
- if (! imageScroll(-50, 0))
- kbdBell();
- break;
-
- case K_RIGHT:
- if (! imageScroll(50, 0))
- kbdBell();
- break;
-
- case K_UP:
- if (! imageScroll(0, -50))
- kbdBell();
- break;
-
- case K_DOWN:
- if (! imageScroll(0, 50))
- kbdBell();
- break;
-
- case '?':
- imageShowInfo(!ImageInfoFlag);
- break;
-
- case 'g':
- imageSetGamma(100, 100, 100);
- break;
-
- case 'G':
- imageSetGamma(70, 70, 70);
- break;
-
- case K_ESCAPE:
- return F_ESC;
- }
-
- } while (delay == K_WAIT);
-
- return 0;
- }
-
- /*
- * imageWarning(format, ...)
- */
- int
- imageWarning(
- char *fmt, /* message format string */
- ... /* optional arguments */
- )
- {
- char buf[120];
- int len;
- font_t *font = DefaultFont;
- int r;
-
- va_list args;
-
- va_start(args, fmt);
-
- (void) vsprintf(buf, fmt, args);
- va_end(args);
-
- len = strlen(buf);
-
- vidDrawText(0, 0, buf, len, font);
- kbdBell();
-
- r = imageGetKey(2);
-
- IRedraw(0, 0, len * font->f_width, font->f_height);
-
- return r;
- }
-
- /*
- * imageError(format, ...)
- */
- int
- imageError(
- char *fmt, /* message format string */
- ... /* optional arguments */
- )
- {
- va_list args;
- static int ErrorTextMode = -1;
- static vmode_t *ErrorTextModeInfo = NULL;
- char line[128];
- int x;
- int i;
- int n;
- int left, top;
-
- va_start(args, fmt);
-
- if (ErrorTextMode == -1)
- {
- ErrorTextMode = bestDisplayMode(V_TEXT_MODE, 80, 25, 0);
- ErrorTextModeInfo = vidModeInfo(ErrorTextMode);
- }
-
- vidSetMode(ErrorTextMode);
- vidClear(0);
-
- left = (ErrorTextModeInfo->width - 60) / 2;
- top = (ErrorTextModeInfo->height - 6) / 2;
-
- memset(line, DBL_HORIZONTAL_LINE, 60);
- line[0] = DBL_TOP_LEFT_CORNER;
- line[59] = DBL_TOP_RIGHT_CORNER;
- vidPutText(left, top, line, 60, 0x00, 0x04);
-
- line[0] = DBL_BOT_LEFT_CORNER;
- line[59] = DBL_BOT_RIGHT_CORNER;
- vidPutText(left, top+5, line, 60, 0x00, 0x04);
-
- memset(line, ' ', 60);
- line[0] = DBL_VERTICAL_LINE;
- line[59] = DBL_VERTICAL_LINE;
- for (i = 1; i < 5; i++)
- vidPutText(left, top + i, line, 60, 0x00, 0x04);
-
- (void) vsprintf(line, fmt, args);
- va_end(args);
-
- n = strlen(line);
- if (n > 58)
- n = 58;
-
- x = left + (60 - n) / 2;
-
- vidPutText(x, top+2, line, n, 0x0e, 0x04);
-
- #if 0
- if (err != 0)
- {
- fmt = errmsg(err);
- n = strlen(fmt);
- if (n > 58)
- n = 58;
-
- x = left + (60 - n) / 2;
-
- vidPutText(x, top+3, fmt, n, 0x0e, 0x04);
- }
- #endif
-
- return imageGetKey(K_WAIT);
- }
-
- /*
- * bestDisplayMode() - returns the "best" available mode for
- * the given resolution and # of colors
- */
- int
- bestDisplayMode(
- int type,
- int width,
- int height,
- int depth
- )
- {
- vmode_t *modes;
- vmode_t *m;
- vmode_t *best = NULL;
- extern int maxdepth;
-
- modes = vidGetModes();
-
- /*
- * first try for a mode that has enough colors
- * and is at least as large as the image
- */
- for (m = modes; m->flags != 0; m++)
- {
- if ( !(m->flags & V_MODE_SUPPORTED) || !(m->flags & type) )
- continue;
-
- if (m->depth > maxdepth)
- continue;
-
- if (m->depth < depth)
- continue;
-
- if (m->width >= width && m->height >= height)
- {
- if (best == NULL || (m->width <= best->width
- && m->height <= best->height && m->depth <= best->depth) )
- best = m;
- }
- }
-
- if (best)
- return best - modes;
-
- /*
- * now try for the best fit that has enough colors
- */
- for (m = modes; m->width != 0; m++)
- {
- if ( !(m->flags & V_MODE_SUPPORTED) || !(m->flags & type) )
- continue;
-
- if (m->depth > maxdepth)
- continue;
-
- if (m->depth < depth)
- continue;
-
- if (best == NULL)
- {
- best = m;
- continue;
- }
-
- if (m->width < best->width || m->height < best->height)
- continue;
-
- best = m;
- }
-
- if (best)
- return best - modes;
-
- /*
- * now try for the best fit from among the modes that
- * have the largest number of colors
- */
- for (m = modes; m->width != 0; m++)
- {
- if ( !(m->flags & V_MODE_SUPPORTED) || !(m->flags & type) )
- continue;
-
- if (m->depth > maxdepth)
- continue;
-
- if (best == NULL)
- {
- best = m;
- continue;
- }
-
- if (m->depth < best->depth)
- continue;
-
- if (m->depth > best->depth)
- {
- best = m;
- continue;
- }
-
- if (best->width < width || best->height < height)
- {
- if (m->width >= best->width && m->height >= best->height)
- best = m;
- }
- else
- {
- if (m->width >= width && m->width <= best->width
- && m->height >= height && m->height <= best->height)
- best = m;
- }
- }
-
- return best - modes;
- }
-
- imageScroll(
- int dx,
- int dy
- )
- {
- int x;
- int y;
-
- static int scroll_in_progress = 0;
- static jmp_buf scroll_unwind;
-
- if (scroll_in_progress)
- longjmp(scroll_unwind, 1);
-
- scroll_in_progress = 1;
- setjmp(scroll_unwind);
-
- x = ImageX + dx;
- if (x > DisplayedImage->width - ScreenModeInfo->width)
- x = DisplayedImage->width - ScreenModeInfo->width;
- if (x < 0)
- x = 0;
-
- y = ImageY + dy;
- if (y > DisplayedImage->height - ScreenModeInfo->height)
- y = DisplayedImage->height - ScreenModeInfo->height;
- if (y < 0)
- y = 0;
-
- if (x == ImageX && y == ImageY)
- {
- scroll_in_progress = 0;
- return 0;
- }
- else
- {
- ImageX = x;
- ImageY = y;
-
- IRedraw(0, 0, ScreenModeInfo->width, ScreenModeInfo->height);
- scroll_in_progress = 0;
- return 1;
- }
- }
-
- imageRedraw()
- {
- int r;
-
- vidClear(ImageBackground);
- vidSetPalette(ImageColorMap, (Image->depth == 4) ? 16 : 256);
- if ((r = IRedraw(0, 0, ScreenModeInfo->width, ScreenModeInfo->height)) != 0)
- return r;
- imageShowInfo(ImageInfoFlag);
- return 0;
- }
-
- /*
- * IRedraw() - redraw screen
- */
-
- IRedraw(
- int x,
- int y,
- int w,
- int h
- )
- {
- /*
- * clip the request to the limits of the physical screen
- */
- if (x < 0)
- {
- w += x;
- x = 0;
- }
-
- if (y < 0)
- {
- h += y;
- y = 0;
- }
-
- #if 1
- if (x & 7)
- {
- w += (x & 7);
- x &= ~7;
- }
-
- if (w & 7)
- w = (w & ~7) + 8;
- #endif
-
- if (DisplayedImage->width - ImageX - x < w)
- w = DisplayedImage->width - ImageX - x;
- if (DisplayedImage->height - ImageY - y < h)
- h = DisplayedImage->height - ImageY - y;
-
- if (ImageInfoFlag && y < (ImageInfoY + ImageInfoHeight)
- && (y + h) >= ImageInfoY)
- {
- while (y < ImageInfoY && h > 0)
- {
- Redraw(x, y, w, 1);
- ++y;
- --h;
- }
-
- while (y < ImageInfoY + ImageInfoHeight && h > 0)
- {
- int x0, x1;
- int w0, w1;
-
- x0 = x;
- w0 = ImageInfoX - x0;
- if (w0 > w)
- w0 = w;
-
- if (w0 > 0)
- Redraw(x0, y, w0, 1);
-
- x1 = ImageInfoX + ImageInfoWidth;
- w1 = x + w - x1;
-
- if (w1 > 0)
- Redraw(x1, y, w1, 1);
-
- ++y;
- --h;
- }
- }
-
- if (w > 0 && h > 0)
- Redraw(x, y, w, h);
-
- return 0;
- }
-
- STATIC void
- IRedraw8(
- int x,
- int y,
- int w,
- int h
- )
- {
- unsigned char *p;
-
-
- while (--h >= 0)
- {
- p = DisplayedImage->pixels[ImageY + y] + ImageX + x;
- vidPutPixels8(x, y, p, w);
- y++;
- }
- }
-
- STATIC void
- IRedraw24(
- int x,
- int y,
- int w,
- int h
- )
- {
- void *p;
-
-
- while (--h >= 0)
- {
- p = DisplayedImage->pixels[ImageY + y] + (ImageX + x) * 3;
- vidPutPixels24(x, y, p, w);
- y++;
- }
- }
-